"""操作审计模块。

该模块提供操作审计功能，记录关键操作以便问题追踪：
- MQTT 连接/断开操作
- MQTT 消息发布操作
- 设备操作（打开详情、属性修改等）
- 配置变更操作
- 错误和异常记录
"""

from __future__ import annotations

import json
import logging
from dataclasses import dataclass, asdict
from datetime import datetime
from typing import Any, Optional

from src.core.logger import setup_audit_logging

# 初始化审计 logger
_audit_logger: Optional[logging.Logger] = None


def _get_audit_logger() -> logging.Logger:
    """获取审计 logger，延迟初始化。"""
    global _audit_logger
    if _audit_logger is None:
        _audit_logger = setup_audit_logging()
    return _audit_logger


@dataclass
class AuditRecord:
    """审计记录数据结构。"""
    
    action: str  # 操作类型，如 "mqtt_connect", "mqtt_publish", "device_open" 等
    timestamp: str  # ISO 格式时间戳
    user: Optional[str] = None  # 用户标识（可选）
    details: Optional[dict[str, Any]] = None  # 操作详情
    result: Optional[str] = None  # 操作结果：success, failed, error
    error_message: Optional[str] = None  # 错误信息（如果有）
    
    def to_dict(self) -> dict[str, Any]:
        """转换为字典格式。"""
        return asdict(self)
    
    def to_json(self) -> str:
        """转换为 JSON 字符串。"""
        return json.dumps(self.to_dict(), ensure_ascii=False, indent=2)


class AuditLogger:
    """操作审计记录器。"""
    
    def __init__(self) -> None:
        self._logger = _get_audit_logger()
    
    def log(
        self,
        action: str,
        *,
        user: Optional[str] = None,
        details: Optional[dict[str, Any]] = None,
        result: Optional[str] = None,
        error_message: Optional[str] = None,
    ) -> None:
        """记录审计日志。
        
        Args:
            action: 操作类型
            user: 用户标识（可选）
            details: 操作详情字典
            result: 操作结果（success, failed, error）
            error_message: 错误信息（如果有）
        """
        record = AuditRecord(
            action=action,
            timestamp=datetime.now().isoformat(),
            user=user,
            details=details,
            result=result,
            error_message=error_message,
        )
        
        # 构建日志消息
        parts = [f"操作: {action}"]
        if user:
            parts.append(f"用户: {user}")
        if result:
            parts.append(f"结果: {result}")
        if details:
            # 简化 details 显示，避免日志过长
            details_str = json.dumps(details, ensure_ascii=False)
            if len(details_str) > 200:
                details_str = details_str[:200] + "..."
            parts.append(f"详情: {details_str}")
        if error_message:
            parts.append(f"错误: {error_message}")
        
        message = " | ".join(parts)
        
        # 根据结果选择日志级别
        if result == "error" or error_message:
            self._logger.error(message)
        elif result == "failed":
            self._logger.warning(message)
        else:
            self._logger.info(message)
    
    def log_mqtt_connect(
        self,
        host: str,
        port: int,
        *,
        username: Optional[str] = None,
        result: str = "success",
        error_message: Optional[str] = None,
    ) -> None:
        """记录 MQTT 连接操作。
        
        Args:
            host: MQTT 服务器地址
            port: MQTT 服务器端口
            username: 用户名（可选）
            result: 连接结果（success, failed, error）
            error_message: 错误信息（如果有）
        """
        details = {
            "host": host,
            "port": port,
        }
        if username:
            details["username"] = username
        
        self.log(
            action="mqtt_connect",
            details=details,
            result=result,
            error_message=error_message,
        )
    
    def log_mqtt_disconnect(
        self,
        *,
        reason: Optional[str] = None,
        error_code: Optional[int] = None,
    ) -> None:
        """记录 MQTT 断开操作。
        
        Args:
            reason: 断开原因
            error_code: 错误码（如果有）
        """
        details = {}
        if reason:
            details["reason"] = reason
        if error_code is not None:
            details["error_code"] = error_code
        
        result = "success" if error_code == 0 else "failed"
        
        self.log(
            action="mqtt_disconnect",
            details=details,
            result=result,
        )
    
    def log_mqtt_publish(
        self,
        topic: str,
        payload: dict[str, Any],
        *,
        result: str = "success",
        error_message: Optional[str] = None,
    ) -> None:
        """记录 MQTT 消息发布操作。
        
        Args:
            topic: MQTT 主题
            payload: 消息负载
            result: 发布结果（success, failed, error）
            error_message: 错误信息（如果有）
        """
        # 提取关键信息，避免记录过大的 payload
        details = {
            "topic": topic,
            "msgid": payload.get("msgid", ""),
            "params_count": len(payload.get("params", {})),
        }
        
        # 如果参数数量较少，记录参数名称
        params = payload.get("params", {})
        if len(params) <= 5:
            details["params"] = list(params.keys())
        
        self.log(
            action="mqtt_publish",
            details=details,
            result=result,
            error_message=error_message,
        )
    
    def log_device_open(
        self,
        device_id: int,
        device_nickname: str,
        *,
        type_name: Optional[str] = None,
    ) -> None:
        """记录打开设备详情操作。
        
        Args:
            device_id: 设备 ID
            device_nickname: 设备昵称
            type_name: 设备类型名称（可选）
        """
        details = {
            "device_id": device_id,
            "device_nickname": device_nickname,
        }
        if type_name:
            details["type_name"] = type_name
        
        self.log(
            action="device_open",
            details=details,
            result="success",
        )
    
    def log_config_change(
        self,
        config_type: str,
        *,
        old_value: Optional[Any] = None,
        new_value: Optional[Any] = None,
        details: Optional[dict[str, Any]] = None,
    ) -> None:
        """记录配置变更操作。
        
        Args:
            config_type: 配置类型（如 "mqtt_config"）
            old_value: 旧值（可选）
            new_value: 新值（可选）
            details: 其他详情（可选）
        """
        change_details = details or {}
        if old_value is not None:
            change_details["old_value"] = str(old_value)
        if new_value is not None:
            change_details["new_value"] = str(new_value)
        
        self.log(
            action=f"config_change_{config_type}",
            details=change_details,
            result="success",
        )
    
    def log_error(
        self,
        error_type: str,
        error_message: str,
        *,
        context: Optional[dict[str, Any]] = None,
    ) -> None:
        """记录错误和异常。
        
        Args:
            error_type: 错误类型
            error_message: 错误消息
            context: 错误上下文信息（可选）
        """
        details = context or {}
        details["error_type"] = error_type
        
        self.log(
            action="error",
            details=details,
            result="error",
            error_message=error_message,
        )


# 全局审计记录器实例
audit_logger = AuditLogger()

